<template>
	<view class="e-scroll-list" ref="scrollListRef">
		<!-- #ifdef APP-NVUE -->
		<!-- nvue使用bindingX实现，以得到更好的性能 -->
		<scroller class="e-scroll-list__scroll-view" ref="scrollListScrollViewRef" scroll-direction="horizontal"
			:show-scrollbar="false" :offset-accuracy="1" @scroll="nvueScrollHandler">
			<view class="e-scroll-list__scroll-view__content">
				<slot />
			</view>
		</scroller>
		<!-- #endif -->
		<!-- #ifndef APP-NVUE -->
		<!-- #ifdef MP-WEIXIN || APP-VUE || H5 || MP-QQ -->
		<!-- 以上平台，支持wxs -->
		<scroll-view class="e-scroll-list__scroll-view" scroll-x @scroll="wxs.scroll" @scrolltoupper="wxs.scrolltoupper"
			@scrolltolower="wxs.scrolltolower" :data-scrollWidth="scrollWidth" :data-barWidth="getPx(props.indicatorBarWidth)"
			:data-indicatorWidth="getPx(props.indicatorWidth)" :show-scrollbar="false" :upper-threshold="0"
			:lower-threshold="0">
		<!-- #endif -->
			<!-- #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ -->
			<!-- 非以上平台，只能使用普通js实现 -->
			<scroll-view class="e-scroll-list__scroll-view" scroll-x @scroll="scrollHandler"
				@scrolltoupper="scrolltoupperHandler" @scrolltolower="scrolltolowerHandler" :show-scrollbar="false"
				:upper-threshold="0" :lower-threshold="0">
			<!-- #endif -->
				<view class="e-scroll-list__scroll-view__content">
					<slot />
				</view>
			</scroll-view>
			<!-- #endif -->
			<view class="e-scroll-list__indicator" v-if="props.indicator" :style="[addStyle(props.indicatorStyle)]">
				<view class="e-scroll-list__indicator__line" :style="[lineStyle]">
					<view class="e-scroll-list__indicator__line__bar" :style="[barStyle]"
						ref="scrollListIndicatorLineBarRef"></view>
				</view>
			</view>
	</view>
</template>
<script lang="ts">
	import { defineComponent } from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	/**
	 * scrollList 横向滚动列表
	 * @description 该组件一般用于同时展示多个商品、分类的场景，也可以完成左右滑动的列表。
	 * @tutorial https://www.uviewui.com/components/scrollList.html
	 * @property {String | Number}	indicatorWidth			指示器的整体宽度 (默认 50 )
	 * @property {String | Number}	indicatorBarWidth		滑块的宽度 (默认 20 )
	 * @property {Boolean}			indicator				是否显示面板指示器 (默认 true )
	 * @property {String}			indicatorColor			指示器非激活颜色 (默认 '#f2f2f2' )
	 * @property {String}			indicatorActiveColor	指示器的激活颜色 (默认 '#3c9cff' )
	 * @property {String | Object}	indicatorStyle			指示器样式，可通过bottom，left，right进行定位
	 * @event {Function} left	滑动到左边时触发
	 * @event {Function} right	滑动到右边时触发
	 * @example
	 */
	export default defineComponent({
		name: "e-scroll-list",
		mixins: [mpMixin],
		methods:{
			scrollEvent (e:'left') {
				this.$emit(e)
			}
		}
	});
</script>

<script src="./scrollWxs.wxs" module="wxs" lang="wxs"></script>


<script setup lang="ts">
	import {
		ref,
		computed,
		toRefs,
		getCurrentInstance,
		onMounted,
	} from 'vue'

	import {
		scrollListProps,
		scrollListEmits
	} from './props'
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import { addStyle, addUnit, getPx } from "../../libs/utils/_utils";
	import {
		os,
		sleep,
		getRect,
		getNvueRect
	} from "../../libs/utils";

	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";
	import type { StyleProperties } from "../../libs/tokens";



	const ctx = getCurrentInstance()

	const {
		scrollList: scrollListDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(scrollListProps)
	const props = useDefaultProps<DefaultProps['scrollList']>(_props, scrollListDefaultProps);

	const emit = defineEmits(scrollListEmits)

	const scrollInfo = ref({
		scrollLeft: 0,
		scrollWidth: 0,
		scrollTop: 0,
		scrollHeight: 0,
		deltaX: 0,
		deltaY: 0
	})
	const scrollWidth = ref(0)
	// 指示器为线型的样式
	const barStyle = computed(() => {

		const style : StyleProperties = {}
		// #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ
		// 此为普通js方案，只有在非nvue和不支持wxs方案的端才使用、
		// 此处的计算理由为：scroll-view的滚动距离与目标滚动距离(scroll-view的实际宽度减去包裹元素的宽度)之比，等于滑块当前移动距离与总需
		// 滑动距离(指示器的总宽度减去滑块宽度)的比值
		const scrollLeft = scrollInfo.value.scrollLeft,
			_scrollWidth = scrollInfo.value.scrollWidth,
			barAllMoveWidth = Number(props.value.indicatorWidth) - Number(props.value.indicatorBarWidth)
		const x = scrollLeft / (_scrollWidth - scrollWidth.value) * barAllMoveWidth
		style.transform = `translateX(${x}px)`
		// #endif
		// 设置滑块的宽度和背景色，是每个平台都需要的
		style.width = addUnit(props.value.indicatorBarWidth)
		style.backgroundColor = props.value.indicatorActiveColor
		return style

	})

	const lineStyle = computed(() => ({
		width: addUnit(props.value.indicatorWidth),
		backgroundColor: props.value.indicatorColor
	}))


	const init = () => {
		getComponentWidth()
	}
	// #ifndef APP-NVUE || MP-WEIXIN || H5 || APP-VUE || MP-QQ
	// scroll-view触发滚动事件
	const scrollHandler = (e: { detail: { scrollLeft: number; scrollWidth: number; scrollTop: number; scrollHeight: number; deltaX: number; deltaY: number; }; }) => {
		scrollInfo.value = e.detail
	}
	const scrolltoupperHandler = () => {
		emit('left')
		scrollInfo.value.scrollLeft = 0
	}
	const scrolltolowerHandler = () => {
		emit('right')
		// 在普通js方案中，滚动到右边时，通过设置scrollInfo.value，模拟出滚动到右边的情况
		// 因为上方是用过computed计算的，设置后，会自动调整滑块的位置
		scrollInfo.value.scrollLeft = getPx(props.value.indicatorWidth) - getPx(props.value.indicatorBarWidth)
	}
	// #endif
	const scrollListRef = ref()
	// 获取组件的宽度
	const getComponentWidth = async () => {
		// 延时一定时间，以获取dom尺寸
		await sleep(30)
		// #ifndef APP-NVUE
		getRect(ctx, '.e-scroll-list').then((size) => {
			scrollWidth.value = size.width!
		})			// #endif

		// #ifdef APP-NVUE
		getNvueRect(scrollListRef.value).then((size) => {
			scrollWidth.value = size.width!
		})
		// #endif
	}
	// #ifdef APP-NVUE
	// 在安卓和iOS上，需要除的倍数不一样，iOS需要除以2
	const actionNum = os() === 'ios' ? 2 : 1
	// 此处不写注释，请自行体会
	const scrollListScrollViewRef = ref()
	const scrollListIndicatorLineBarRef = ref()
	let BindingX:any
	const nvueScrollHandler = (e : { contentSize : { width : number } }) => {

		// const scrollLeft = e.contentOffset.x
		const contentSize = e.contentSize.width
		const barAllMoveWidth = Number(props.value.indicatorWidth) - Number(props.value.indicatorBarWidth)

		const expression = `(x / ${actionNum}) / ${contentSize - scrollWidth.value} * ${barAllMoveWidth}`
		BindingX.bind({
			anchor: scrollListScrollViewRef.value,
			eventType: 'scroll',
			props: [{
				element: scrollListIndicatorLineBarRef.value,
				property: 'transform.translateX',
				expression
			}]
		})
	}

	// #endif
	




	onMounted(() => {
		init()
		// #ifdef APP-NVUE
		BindingX = uni.requireNativePlugin('bindingx')
		// #endif
	})
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/scroll-list.scss";
</style>